-- 给剪刀添加专属的燃料类别,使得金块可以给剪刀添加燃料
FUELTYPE.ASSN_JIANDAO = "ASSN_JIANDAO" -- FUELTYPE 全局表中新增燃料类别 ASSN_JIANDAO
local item_fuel =
{
    nightmarefuel = 5,          -- 噩梦燃料
    goldnugget = 10,            -- 金块
    axe = 10,                   -- 斧头
    goldenaxe = 20,             -- 黄金斧头
    pickaxe = 10,               -- 鹤嘴锄
    goldenpickaxe = 20,         -- 黄金鹤嘴锄
    pitchfork = 10,             -- 干草叉
    goldenpitchfork = 20,       -- 黄金干草叉
    hammer = 10,                -- 锤子
    shovel = 10,                -- 铲子
    goldenshovel = 20,          -- 黄金铲子
    farm_hoe = 10,              -- 园艺锄
    golden_farm_hoe = 20,       -- 黄金园艺锄
    farm_plow = 10,             -- 耕地机
    multitool_axe_pickaxe = 50, -- 多用斧稿
}

for k, v in pairs(item_fuel) do
    AddPrefabPostInit(k, function(inst)
        inst:AddTag("ASSN_JIANDAO")
        if not TheWorld.ismastersim then return end
        inst:AddComponent("assn_fuel")
        inst.components.assn_fuel.fuelvalue = v
    end)
end

-- 给噩梦燃料添加可食用组件,仅刺客567可以食用
FOODTYPE.NIGHTMARE = "NIGHTMARE"

local function MakeNightmareFuelEdible(inst)
    inst:AddTag("edible_" .. FOODTYPE.NIGHTMARE)

    if not TheWorld.ismastersim then return end

    if not inst.components.edible then
        inst:AddComponent("edible")
    end

    inst.components.edible.healthvalue = 10
    inst.components.edible.hungervalue = 10
    inst.components.edible.sanityvalue = 10
    inst.components.edible.foodtype = FOODTYPE.NIGHTMARE
end

AddPrefabPostInit("nightmarefuel", MakeNightmareFuelEdible)

-- 剪刀飞回玩家可以直接接到且不会对玩家造成伤害
local function HookHit(self)
    local _OldProjectileHit = self.Hit
    self.Hit = function(self, target, ...)
        if self.inst.prefab == "assn_jiandao" and target == self.owner then
            if target and target.components and target.components.inventory then
                if self.inst.components.equippable ~= nil and
                    not target.components.inventory:GetEquippedItem(self.inst.components.equippable.equipslot) then
                    target.components.inventory:Equip(self.inst)
                else
                    target.components.inventory:GiveItem(self.inst)
                end
                target:PushEvent("catch")
            end
            if self.delayowner ~= nil then
                self.inst:RemoveEventCallback("onremove", self._ondelaycancel, self.delayowner)
                self.inst:RemoveEventCallback("newstate", self._ondelaycancel, self.delayowner)
                self.delayowner = nil
            end
            self:Stop()
            self.inst.Physics:Stop()
            self.inst._returning = nil
            return
        end
        _OldProjectileHit(self, target, ...)
    end
end
AddComponentPostInit("projectile", HookHit)

-- 魔刀千刃无视攻击目标15%的防御,对穿了护甲装备的无效,仅针对自身有防御能力的,貌似只有狂暴克劳斯,石虾还有泰拉mod里的生物,该设定才起作用
local function HookDoDelta(self)
    local Old_DoDelta = self.DoDelta
    self.DoDelta = function(self, amount, overtime, cause, ignore_invincible, afflicter, ignore_absorb, ...)
        if afflicter ~= nil and afflicter.components.inventory ~= nil then
            local afflicter_weapon = afflicter.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
            if afflicter_weapon == nil then
                return Old_DoDelta(self, amount, overtime, cause, ignore_invincible, afflicter, ignore_absorb, ...)
            end
            if amount < 0 and afflicter_weapon.prefab == "assn_qianren" and not ignore_absorb then
                if afflicter_weapon.skill and afflicter_weapon.skill == 2 then
                    -- 开启了真实之怒,无视目标任何自带防御
                    ignore_absorb = true
                else
                    -- 没有开启真实之怒,计算目标的防御,依照15%减伤基础,造成更多的伤害
                    local absorb = 0

                    -- 推算目标当前吸收率（注意 combat 不一定拥有完整攻击数据）
                    absorb = self.absorb or 0
                    if self.playerabsorb ~= nil and afflicter ~= nil and afflicter:HasTag("player") then
                        absorb = absorb + self.playerabsorb
                    end

                    absorb = math.clamp(absorb, 0, 1)

                    local reduced_absorb = math.max(absorb - 0.15, 0)
                    local raw_effective = (1 - absorb)
                    local fake_effective = (1 - reduced_absorb)

                    if raw_effective > 0 then
                        amount = amount / (raw_effective / fake_effective)
                        -- TheNet:Announce(amount)
                    end
                end
            end
        end
        if self.inst ~= nil and self.inst.components.inventory ~= nil then
            local inst_weapon = self.inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
            if inst_weapon and inst_weapon.prefab == "assn_qianren" then
                if inst_weapon.skill and inst_weapon.skill == 2 then
                    -- 开启了真实之怒,减少50%的伤害
                    amount = amount * 0.8
                elseif inst_weapon.skill and inst_weapon.skill == 3 then
                    amount = amount * 0.5
                end
            end
        end

        return Old_DoDelta(self, amount, overtime, cause, ignore_invincible, afflicter, ignore_absorb, ...)
    end
end
AddComponentPostInit("health", HookDoDelta)

-- 魔刀千刃开启真实之怒后无视任何防御,包括穿戴护甲的单位
local function HookInventoryApplyDamage(self)
    local Old_ApplyDamage = self.ApplyDamage
    self.ApplyDamage = function(self, damage, attacker, weapon, spdamage, ...)
        if weapon and weapon.prefab == "assn_qianren" then
            if weapon.skill and weapon.skill == 2 then
                -- 开启了真实之怒,无视目标护甲,直接造成伤害
                return damage, spdamage
            end
        end
        return Old_ApplyDamage(self, damage, attacker, weapon, spdamage, ...)
    end
end
AddComponentPostInit("inventory", HookInventoryApplyDamage)

-- 给部分物品添加可以交易的组件
local function AddTradableToPrefab(prefab_name)
    AddPrefabPostInit(prefab_name, function(inst)
        if not TheWorld.ismastersim then
            return
        end

        if inst.components.tradable == nil then
            inst:AddComponent("tradable")
        end
    end)
end
-- 添加 Tradable 组件到目标物品
local target_items = { "nightmarefuel" }
for _, prefab_name in ipairs(target_items) do
    AddTradableToPrefab(prefab_name)
end

-- 人物本地的hook
AddPrefabPostInit("player_classified", function(inst)
    --添加物品详细信息
    inst.assn_info = "" --详细信息
    inst.net_assn_info = _G.net_string(inst.GUID, "assn_info", "assn_infodirty")
    if TheNet:GetIsClient() or (TheNet:GetIsServer() and not TheNet:IsDedicated()) then
        --添加物品详细信息
        inst:ListenForEvent("assn_infodirty", function(inst)
            inst.assn_info = inst.net_assn_info:value()
        end)
    end
end)

-- hook玩家鼠标停留函数
-- 返回物品详细信息
local function CheckUserHint(inst)
    local classified = ThePlayer and ThePlayer.player_classified
    if classified == nil then
        return ""
    end
    local i = string.find(classified.assn_info, ';', 1, true)
    if i == nil then
        return ""
    end
    local guid = tonumber(classified.assn_info:sub(1, i - 1))
    if guid ~= inst.GUID then
        return ""
    end
    return classified.assn_info:sub(i + 1)
end
local save_target         -- 暂存目标
local last_check_time = 0 -- 上一次检查时间
AddClassPostConstruct("widgets/hoverer", function(hoverer)
    local oldSetString = hoverer.text.SetString
    hoverer.text.SetString = function(text, str, ...)
        -- 获取目标
        local target = GLOBAL.TheInput:GetHUDEntityUnderMouse()
        target = (target and target.widget and target.widget.parent ~= nil and target.widget.parent.item) or TheInput:GetWorldEntityUnderMouse() or nil
        -- 获取需显示信息
        if target and target.GUID and target:HasTag("showassninfo") then
            local str2 = CheckUserHint(target)
            if str2 and str2 ~= "" then
                str = str .. str2
            end
            -- 目标变了或者时间间隔1秒，则发送rpc
            if target ~= save_target or last_check_time + 1 < GetTime() then
                save_target = target
                last_check_time = GetTime()
                SendModRPCToServer(MOD_RPC.ScissorMod.Showinfo, save_target.GUID, save_target)
            end
        end

        if oldSetString then
            return oldSetString(text, str, ...)
        end
    end
end)

-- 被攻击不会僵直
AddStategraphPostInit("wilson", function(sg)
    -- 玩家拥有免僵直标签时被攻击不会僵直
    if sg.events and sg.events.attacked then
        local oldattackedfn = sg.events.attacked.fn
        sg.events.attacked.fn = function(inst, data)
            -- 这里顺便加个playerghost的判断，免得玩家濒死的时候又挨了一下揍报错
            if inst:HasTag("ASSN_QIANREN_SKILL") or inst:HasTag("playerghost") then
                return
            elseif oldattackedfn then
                return oldattackedfn(inst, data)
            end
        end
    end
end)

-- 玩家本地参数:经验,等级,体力
local function OnExpboosterDirty(inst)
    if inst._parent ~= nil then
        local assn_currentlevel = inst.assn_currentlevel:value()
        local assn_maxlevel = inst.assn_maxlevel:value()
        local assn_currentexp = inst.assn_currentexp:value()
        local data =
        {
            assn_currentlevel = assn_currentlevel,
            assn_maxlevel = assn_maxlevel,
            assn_currentexp = assn_currentexp,
        }
        inst._parent:PushEvent("expboosterchanges", data)
    end
end

local function OnStaminaDirty(inst)
    if inst._parent ~= nil then
        local assn_stamina_current = inst.assn_stamina_current:value()
        local assn_stamina_max = inst.assn_stamina_max:value()
        local data =
        {
            assn_stamina_current = assn_stamina_current,
            assn_stamina_max = assn_stamina_max,
        }
        inst._parent:PushEvent("staminachanges", data)
    end
end

AddPrefabPostInit("player_classified", function(inst)
    -- 567等级经验相关
    inst.assn_currentlevel = net_ushortint(inst.GUID, "expbooster.currentlevel", "expboosterdirty")
    inst.assn_maxlevel = net_ushortint(inst.GUID, "expbooster.maxlevel", "expboosterdirty")
    inst.assn_currentexp = net_ushortint(inst.GUID, "expbooster.currentexp", "expboosterdirty")
    inst.assn_currentlevel:set(0)
    inst.assn_maxlevel:set(100)
    inst.assn_currentexp:set(0)
    inst:ListenForEvent("expboosterdirty", OnExpboosterDirty)

    -- 567体力相关
    inst.assn_stamina_current = net_ushortint(inst.GUID, "stamina.current", "staminadirty")
    inst.assn_stamina_max = net_ushortint(inst.GUID, "stamina.max", "staminadirty")
    inst.assn_stamina_current:set(80)
    inst.assn_stamina_max:set(80)
    inst:ListenForEvent("staminadirty", OnStaminaDirty)

    if not TheWorld.ismastersim then
        return
    end
end)

local Widget = require "widgets/widget"
local RequireLevelWidget = require "widgets/assn_levelwidget"
local RequireStaminaWidget = require "widgets/assn_stamina_widget"

-- 扩展 Controls（所有客户端都会执行）
AddClassPostConstruct("widgets/controls", function(self, owner)
    if owner.prefab == "assn_567" then
        --  左下角放一个 widgetRoot，然后加我们的小组件
        self.assn_level_root = self:AddChild(Widget("AssnLevelRoot"))
        self.assn_level_root:SetScaleMode(SCALEMODE_PROPORTIONAL)
        self.assn_level_root:SetHAnchor(ANCHOR_LEFT)
        self.assn_level_root:SetVAnchor(ANCHOR_BOTTOM)
        self.assn_level_root:SetPosition(180, 90) -- 可自行调整位置

        self.assn_level_widget = self.assn_level_root:AddChild(RequireLevelWidget(owner))
        self.assn_stamina_widget = self.assn_level_root:AddChild(RequireStaminaWidget(owner))
    end
end)

-- 等级经验变换时更新函数
local function OnExpboosterChanged(inst, data)
    ThePlayer.HUD.controls.assn_level_widget:OnUpdate(data.assn_currentlevel, data.assn_currentexp, 100)
end

-- 体力变换时更新函数
local function OnStaminaChanged(inst, data)
    ThePlayer.HUD.controls.assn_stamina_widget:OnUpdate(data.assn_stamina_current, data.assn_stamina_max)
end

-- hook玩家
AddPlayerPostInit(function(inst)
    if not TheNet:IsDedicated() and inst:HasTag("assn_567") and inst.prefab == "assn_567" then
        inst:ListenForEvent("expboosterchanges", OnExpboosterChanged)
        inst:ListenForEvent("staminachanges", OnStaminaChanged)
    end
    if not TheWorld.ismastersim then
        return
    end
end)
